use serde::{Deserialize, Serialize};
use serde_json::Value;

/// Built-in tool definitions for agents
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BuiltinTool {
    pub name: String,
    pub description: String,
    pub parameters: Value,
}

/// Calculator tool for arithmetic operations
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CalculatorArgs {
    pub operation: String,
    pub operands: Vec<f64>,
}

impl BuiltinTool {
    /// Create a calculator tool
    pub fn calculator() -> Self {
        Self {
            name: "calculator".to_string(),
            description: "Perform arithmetic operations like addition, subtraction, multiplication, and division".to_string(),
            parameters: serde_json::json!({
                "type": "object",
                "properties": {
                    "operation": {
                        "type": "string",
                        "enum": ["add", "subtract", "multiply", "divide"],
                        "description": "The arithmetic operation to perform"
                    },
                    "operands": {
                        "type": "array",
                        "items": {
                            "type": "number"
                        },
                        "description": "The numbers to operate on"
                    }
                },
                "required": ["operation", "operands"]
            }),
        }
    }

    /// Create a search tool
    pub fn search() -> Self {
        Self {
            name: "search".to_string(),
            description: "Search for information using a search engine".to_string(),
            parameters: serde_json::json!({
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "The search query"
                    },
                    "limit": {
                        "type": "number",
                        "description": "Maximum number of results to return",
                        "default": 5
                    }
                },
                "required": ["query"]
            }),
        }
    }

    /// Create a knowledge base search tool
    pub fn kb_search() -> Self {
        Self {
            name: "kb_search".to_string(),
            description: "Search the knowledge base for relevant information".to_string(),
            parameters: serde_json::json!({
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "The search query"
                    },
                    "limit": {
                        "type": "number",
                        "description": "Maximum number of results to return",
                        "default": 5
                    }
                },
                "required": ["query"]
            }),
        }
    }

    /// Create an image generation tool
    pub fn image_generation() -> Self {
        Self {
            name: "image_generation".to_string(),
            description: "Generate images based on a text prompt".to_string(),
            parameters: serde_json::json!({
                "type": "object",
                "properties": {
                    "prompt": {
                        "type": "string",
                        "description": "The text prompt to generate an image from"
                    },
                    "width": {
                        "type": "number",
                        "description": "Width of the generated image",
                        "default": 512
                    },
                    "height": {
                        "type": "number",
                        "description": "Height of the generated image",
                        "default": 512
                    }
                },
                "required": ["prompt"]
            }),
        }
    }
}

/// Execute a calculator operation
pub fn execute_calculator(args: &CalculatorArgs) -> Result<f64, String> {
    if args.operands.is_empty() {
        return Err("No operands provided".to_string());
    }

    match args.operation.as_str() {
        "add" => Ok(args.operands.iter().sum()),
        "subtract" => {
            if args.operands.len() == 1 {
                Ok(-args.operands[0])
            } else {
                Ok(args.operands[1..]
                    .iter()
                    .fold(args.operands[0], |acc, &x| acc - x))
            }
        }
        "multiply" => Ok(args.operands.iter().fold(1.0, |acc, &x| acc * x)),
        "divide" => {
            if args.operands.contains(&0.0)
                && args.operands.iter().position(|&x| x == 0.0) != Some(0)
            {
                Err("Division by zero".to_string())
            } else if args.operands.len() == 1 {
                Ok(1.0 / args.operands[0])
            } else {
                Ok(args.operands[1..]
                    .iter()
                    .fold(args.operands[0], |acc, &x| acc / x))
            }
        }
        _ => Err(format!("Unknown operation: {}", args.operation)),
    }
}

/// Execute a search operation (placeholder)
pub fn execute_search(query: &str, _limit: Option<usize>) -> Result<Vec<String>, String> {
    // This would integrate with a real search engine in a full implementation
    Ok(vec![
        format!("Search result 1 for: {}", query),
        format!("Search result 2 for: {}", query),
        format!("Search result 3 for: {}", query),
    ])
}

/// Execute a knowledge base search (placeholder)
pub fn execute_kb_search(query: &str, _limit: Option<usize>) -> Result<Vec<String>, String> {
    // This would search the actual knowledge base in a full implementation
    Ok(vec![
        format!("KB result 1 for: {}", query),
        format!("KB result 2 for: {}", query),
    ])
}

/// Execute an image generation operation (placeholder)
pub fn execute_image_generation(
    prompt: &str,
    _width: Option<u32>,
    _height: Option<u32>,
) -> Result<String, String> {
    // This would generate an actual image in a full implementation
    Ok(format!("Generated image based on prompt: {}", prompt))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_calculator() {
        let args = CalculatorArgs {
            operation: "add".to_string(),
            operands: vec![1.0, 2.0, 3.0],
        };
        assert_eq!(execute_calculator(&args), Ok(6.0));

        let args = CalculatorArgs {
            operation: "multiply".to_string(),
            operands: vec![2.0, 3.0, 4.0],
        };
        assert_eq!(execute_calculator(&args), Ok(24.0));

        let args = CalculatorArgs {
            operation: "divide".to_string(),
            operands: vec![10.0, 2.0],
        };
        assert_eq!(execute_calculator(&args), Ok(5.0));
    }

    #[test]
    fn test_search_tools() {
        assert!(execute_search("test query", Some(5)).is_ok());
        assert!(execute_kb_search("test query", Some(5)).is_ok());
        assert!(execute_image_generation("test prompt", Some(512), Some(512)).is_ok());
    }
}
